﻿using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcSupplantCaching
{
    /// <summary>
    /// Holds the extension methods for supplanting content and actions onto an output cached page.
    /// </summary>
    public static class HtmlHelperExtensions
    {
        /// <summary>
        /// Supplants the provided content onto the page after the output cached page has been retreived.
        /// </summary>
        /// <param name="html">The HtmlHelper used to supplant content with. If the response stream is not valid on <paramref name="html"/>, an empty string will be rendered.</param>
        /// <param name="supplantFunc">A function that returns a string of content to be supplanted onto the output cached page.</param>
        /// <returns>A string token that represents the data that is to be supplanted when the <paramref name="supplantFunc"/> is executed.</returns>
        public static HtmlString SupplantContent(this HtmlHelper html, Func<string> supplantFunc)
        {
            if (html.ViewContext.HttpContext.Response.Output == null) return new HtmlString(string.Empty);

            string key = Guid.NewGuid().ToString();
            OutputCache.SupplantProvider.Add(key, supplantFunc, DateTime.UtcNow.AddSeconds(300));
            string content = string.Format(SupplantOutputCacheAttribute.SupplantTokenFormat, key);

            // If this isn't a cacheable response, the supplant should run immedietely.
            if (!html.ViewContext.HttpContext.Response.Headers.AllKeys.Contains(SupplantOutputCacheAttribute.CacheableHeaderKey))
            {
                content = supplantFunc();
            }
            return new HtmlString(content);
        }

        /// <summary>
        /// Supplants the provided content onto the page after the output cached page has been retreived.
        /// </summary>
        /// <param name="html">The HtmlHelper used to supplant content with. If the response stream is not valid on <paramref name="html"/>, an empty string will be rendered.</param>
        /// <param name="supplantFunc">A function that returns an IHtmlString of content to be supplanted onto the output cached page.</param>
        /// <returns>A string token that represents the data that is to be supplanted when the <paramref name="supplantFunc"/> is executed.</returns>
        public static HtmlString SupplantContent(this HtmlHelper html, Func<IHtmlString> supplantFunc)
        {
            if (html.ViewContext.HttpContext.Response.Output == null) return new HtmlString(string.Empty);

            string key = Guid.NewGuid().ToString();
            OutputCache.SupplantProvider.Add(key, supplantFunc, DateTime.UtcNow.AddSeconds(300));
            string content = string.Format(SupplantOutputCacheAttribute.SupplantTokenFormat, key);

            // If this isn't a cacheable response, the supplant should run immedietely.
            if (!html.ViewContext.HttpContext.Response.Headers.AllKeys.Contains(SupplantOutputCacheAttribute.CacheableHeaderKey))
            {
                content = supplantFunc().ToString();
            }
            return new HtmlString(content);
        }

        /// <summary>
        /// Allows an <see cref="Action"/> to run after the output cached page has been retreived.
        /// </summary>
        /// <param name="html">The HtmlHelper used to supplant content with. If the response stream is not valid on <paramref name="html"/>, an empty string will be rendered.</param>
        /// <param name="supplantAction">The <see cref="Action"/> to be run.</param>
        /// <returns>A string token that represents the data that is to be supplanted when the <paramref name="supplantAction"/> is executed.</returns>
        public static HtmlString SupplantAction(this HtmlHelper html, Action supplantAction)
        {
            if (html.ViewContext.HttpContext.Response.Output == null) return new HtmlString(string.Empty);

            string key = Guid.NewGuid().ToString();
            OutputCache.SupplantProvider.Add(key, supplantAction, DateTime.UtcNow.AddSeconds(300));

            // If this isn't a cacheable response, the supplant should run immedietely.
            if (!html.ViewContext.HttpContext.Response.Headers.AllKeys.Contains(SupplantOutputCacheAttribute.CacheableHeaderKey))
            {
                supplantAction();
            }
            return new HtmlString(string.Format(SupplantOutputCacheAttribute.SupplantTokenFormat, key));
        }
    }
}